﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Data.Linq;
using System.ComponentModel;
using System.Web.Mvc;
using Vit.Common.Extensions;
using Vit.Web.Data;
using Vit.Web.Extensions;
using Vit.Web.Mvc.Results;
using Vit.Web.Validation;

namespace Vit.Web.Mvc
{
    public abstract class EntityRuleControllerBase<TRule, TContext, TEntity> : Controller
        where TRule : EntityRuleBase<TContext, TEntity>
        where TContext : DataContext, new()
        where TEntity : class, new()
    {
        protected TRule rule;

        public EntityRuleControllerBase(TRule rule)
        {
            this.rule = rule;
        }

        protected abstract IQueryable<TEntity> QueryWithFilter(IQueryable<TEntity> query, object filterObject);
        protected abstract object CreateFilterObject();
        protected abstract TEntity GetEntityWithId(string id);

        [HttpGet]
        public virtual ActionResult Index([DefaultValue(0)]int id)
        {
            ViewData["FilterObject"] = CreateFilterObject();
            var query = rule.Query(null);
            if (id > 0 || AlwaysPaging)
            {
                PageOfList<TEntity> result = new PageOfList<TEntity>(query, id, PageSize);
                return View(result);
            }
            else
            {
                return View(query);
            }
        }

        [HttpPost]
        public virtual ActionResult Index([DefaultValue(0)]int id, FormCollection form)
        {
            object searchObj = CreateFilterObject();
            ViewData["FilterObject"] = searchObj;

            var query = rule.Query(null);
            query = QueryWithFilter(query, searchObj);
            if (id > 0 || AlwaysPaging)
            {
                PageOfList<TEntity> result = new PageOfList<TEntity>(query, id, PageSize);
                return View(result);
            }
            else
            {
                return View(query);
            }
        }

        [HttpGet]
        public virtual ActionResult Dialog([DefaultValue(0)]int id, string field, string selected)
        {
            ViewData["FilterObject"] = CreateFilterObject();
            ViewData["Field"] = field;
            ViewData["Selected"] = selected;
            var query = rule.Query(null);
            if (id > 0 || AlwaysPaging)
            {
                PageOfList<TEntity> result = new PageOfList<TEntity>(query, id, PageSize);
                return View(result);
            }
            else
            {
                return View(query);
            }
        }

        [HttpPost]
        public virtual ActionResult Dialog([DefaultValue(0)]int id, string field, string selected, FormCollection form)
        {
            object searchObj = CreateFilterObject();
            ViewData["FilterObject"] = searchObj;
            ViewData["Field"] = field;
            ViewData["Selected"] = selected;

            var query = rule.Query(null);
            query = QueryWithFilter(query, searchObj);
            if (id > 0 || AlwaysPaging)
            {
                PageOfList<TEntity> result = new PageOfList<TEntity>(query, id, PageSize);
                return View(result);
            }
            else
            {
                return View(query);
            }
        }

        [HttpGet]
        public virtual ActionResult Create()
        {
            TEntity obj = new TEntity();
            return View("Edit", obj);
        }

        [HttpPost]
        public virtual ActionResult Create(TEntity obj)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    rule.Insert(obj);
                    return RedirectToAction("Index");
                }
                catch (ValidationException ex)
                {
                    this.ModelState.AddModelErrors(ex.ValidationState);
                    return View("Edit", obj);
                }
            }
            else
            {
                return View("Edit", obj);
            }
        }

        [HttpGet]
        public virtual ActionResult Detail(string id)
        {
            TEntity entity = GetEntityWithId(id);
            if (entity != null)
            {
                var obj = rule.FirstOrDefault(rule.GetEntityKeyPredict(entity));
                return View(obj);
            }
            return new PartialErrorResult(string.Format("RecordsNotFound", id));
        }

        [HttpGet]
        public virtual ActionResult Edit(string id)
        {
            TEntity entity = GetEntityWithId(id);
            if (entity != null)
            {
                var obj = rule.FirstOrDefault(rule.GetEntityKeyPredict(entity));
                return View(obj);
            }
            return new PartialErrorResult(string.Format("RecordsNotFound", id));
        }

        [HttpPost]
        public virtual ActionResult Edit(TEntity obj)
        {
            if (this.ModelState.IsValid)
            {
                try
                {
                    var entity = rule.FirstOrDefault(rule.GetEntityKeyPredict(obj));
                    this.UpdateModel<TEntity>(entity);
                    entity = rule.Update(entity);
                    return View(entity);
                }
                catch (ValidationException ex)
                {
                    this.ModelState.AddModelErrors(ex.ValidationState);
                    return View("Edit", obj);
                }

            }
            else
            {
                return View(obj);
            }
        }

        [HttpGet]
        public virtual ActionResult Delete(string id)
        {
            TEntity entity = GetEntityWithId(id);
            if (entity != null)
            {
                rule.Delete(entity);
                return RedirectToAction("Index");
            }
            return new PartialErrorResult(string.Format("RecordsNotFound", id));
        }

        [HttpPost]
        public virtual ActionResult Delete(FormCollection form)
        {
            foreach (string fid in form.AllKeys.Where(o => o.StartsWith("cb_")))
            {
                string val = form[fid];

                if (string.IsNullOrEmpty(val) || val.ConvertTo<bool>(false) == false)
                    continue;

                val = fid.Substring(3);
                TEntity entity = GetEntityWithId(val);
                if (entity != null)
                    rule.DeleteOnSubmit(entity);
            }
            rule.SubmitChanges();
            return RedirectToAction("Index");
        }

        protected virtual int PageSize
        {
            get
            {
                return 3;
            }
        }

        protected virtual bool AlwaysPaging
        {
            get
            {
                return true;
            }
        }
    }
}
